#include "Col.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "Metric.h"

#include "Class.h"
#include "String.h"
#include "Math.h"
#include "ET_stdio.h"

SimpleMetaImpl(Metric)
{
	len= len;
	Metric *m= (Metric*) addr;
	if (! isptr)
		sprintf(buf, "w: %d  h: %d  b: %d", m->extent.x, m->extent.y, m->base);
}

Metric::Metric()
{
	extent.x= extent.y= base= 0;
}

Metric::Metric(const Point &e, int b) : extent(e), base(b)
{
}

Metric::Metric(const Point &e) : extent(e), base(e.y)
{
}

Metric::Metric(int w)
{
	extent.x= extent.y= w;
	base= w;
}

Metric::Metric(int w, int h)
{
	extent.x= w;
	base= extent.y= h;
}

Metric::Metric(int w, int h, int b)
{
	extent.x= w;
	extent.y= h;
	base= b;
}

Metric::Metric(const Metric &m) : extent(m.extent), base(m.base)
{
}

Metric Metric::Inset(const Point &e)
{
	extent-= 2*e;
	base-= e.y;
	return *this;
}

Metric Metric::Expand(const Point &e)
{
	extent+= 2*e;
	base+= e.y;
	return *this;
}

Metric Metric::Merge(const Metric &m)
{
	extent.x= Math::Max(extent.x, m.extent.x);
	base= Math::Max(base, m.base);
	int descender= Math::Max(extent.y-base, m.extent.y-m.base);
	extent.y= base+descender;
	return *this;
}

Metric Metric::Cat(Direction d, const Metric &m, const Point &gap)
{
	if (d == eVert) {
		extent.x= Math::Max(extent.x, m.extent.x);
		extent.y+= m.extent.y + gap.y;
		base= extent.y;
	} else {        // eHor
		base= Math::Max(base, m.base);
		extent.x+= m.extent.x + gap.x;
		extent.y= base+Math::Max(extent.y-base, m.extent.y-m.base);
	}
	return *this;
}

Metric HCat(const Metric &m1, const Metric &m2, int hgap)
{
	Metric m;
	m.base= Math::Max(m1.base, m2.base);
	m.extent.x= m1.extent.x + m2.extent.x + hgap;
	m.extent.y= m.base+Math::Max(m1.extent.y-m1.base, m2.extent.y-m2.base);
	return m;
}

Metric VCat(const Metric &m1, const Metric &m2, int vgap)
{
	Metric m;
	m.extent.x= Math::Max(m1.extent.x, m2.extent.x);
	m.base= m.extent.y= m1.extent.y + m2.extent.y + vgap;
	// m.base= m.extent.y/2;
	return m;
}

Metric Cat(Direction d, const Metric &m1, const Metric &m2, const Point &gap)
{
	if (d == eVert)
		return VCat(m1, m2, gap.y);
	return HCat(m1, m2, gap.x);
}

Metric Min(const Metric &m1, const Metric &m2)
{
	Metric m;
	m.extent.x= Math::Min(m1.extent.x, m2.extent.x);
	m.base= Math::Min(m1.base, m2.base);
	int descender= Math::Min(m1.extent.y-m1.base, m2.extent.y-m2.base);
	m.extent.y= descender+m.base;
	return m;
}

Metric Max(const Metric &m1, const Metric &m2)
{
	Metric m;
	m.extent.x= Math::Max(m1.extent.x, m2.extent.x);
	m.base= Math::Max(m1.base, m2.base);
	int descender= Math::Max(m1.extent.y-m1.base, m2.extent.y-m2.base);
	m.extent.y= descender+m.base;
	return m;
}

OStream& operator<< (OStream &s, const Metric &m)
{
	return s << m.extent SP << m.base SP;
}

IStream& operator>> (IStream &s, Metric &m)
{
	return s >> m.extent >> m.base;
}


